Skip to content

Move OrtModelPackageApi to the experimental C API#28990

Merged
jambayk merged 5 commits into
mainfrom
jambayk/mp-experimental
Jun 11, 2026
Merged

Move OrtModelPackageApi to the experimental C API#28990
jambayk merged 5 commits into
mainfrom
jambayk/mp-experimental

Conversation

@jambayk

@jambayk jambayk commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description

Move the existing model package C API off the stable OrtApi onto the experimental name-based lookup mechanism added in #28746. Each model package function is registered individually in include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc with the OrtModelPackageApi_ prefix and the _SinceV28 version suffix, following the lifecycle rules in docs/design/Experimental_C_API.md.

Headline changes:

  • OrtApi::GetModelPackageApi, the OrtModelPackageApi struct, OrtApis::GetModelPackageApi, the OrtModelPackageAPI namespace, onnxruntime/core/session/model_package_api.h, and the C++ wrappers (Ort::GetModelPackageApi, ORT_DEFINE_RELEASE_FROM_API_STRUCT(ModelPackage*), ModelPackageOptions/Context/ComponentContext) are removed.
  • Opaque handle types (OrtModelPackageOptions, OrtModelPackageContext, OrtModelPackageComponentContext) move into onnxruntime_experimental_c_api.h.
  • All 15 model package functions are registered in onnxruntime_experimental_c_api.inc. Impls move into namespace OrtExperimentalApis with _SinceV28-suffixed names in model_package_api.cc; bodies are unchanged.
  • experimental_c_api.cc gains a forward-decl block (driven by the same .inc X-macro) so the auto-generated registration table can take the address of every entry, even those defined in model_package_api.cc.
  • The Python bindings (PyModelPackageContext / PyModelPackageOptions / PyModelPackageComponentContext and their onnxruntime.__init__ exports) are removed. Per the design doc we start the experimental API in C/C++ only.
  • onnxruntime/test/autoep/test_model_package.cc switches to a local ModelPackageFns struct populated through the Ort::Experimental::Get_OrtModelPackageApi_*_Fn(api) typed accessors.

Consumer usage going forward, in C++:

#include "onnxruntime_c_api.h"
#include "onnxruntime_experimental_c_api.h"

const OrtApi* ort = OrtGetApiBase()->GetApi(ORT_API_VERSION);

if (auto* fn = Ort::Experimental::Get_OrtModelPackageApi_CreateModelPackageContext_SinceV28_Fn(ort)) {
  OrtModelPackageContext* ctx = nullptr;
  Ort::ThrowOnError(fn(ORT_TSTR("/path/to/pkg"), &ctx));
  // ...
}

Motivation and Context

The model package API was added to the stable OrtApi in 1.27 but has not shipped in a release yet. Now that #28746 has landed the experimental C API framework, the right home for an iterating preview surface like model package is behind OrtApi::GetExperimentalFunction, not on the stable struct.

Moving it to experimental:

  • frees us to change signatures (each name is uniquely versioned) without breaking the stable ABI;
  • gives consumers a clear "is this specific thing available?" contract instead of a struct that looks stable but isn't;
  • lets the surface be promoted to stable cleanly later (move entries to OrtApi, drop the _SinceV<N> suffix, remove the experimental entries).

jambayk and others added 2 commits June 10, 2026 19:29
Move the model package C surface off the stable OrtApi onto the
experimental name-based lookup added in #28746. Each function is
registered individually in onnxruntime_experimental_c_api.inc with
the OrtModelPackageApi_ prefix and the _SinceV28 version suffix,
matching the lifecycle rules in docs/design/Experimental_C_API.md.

- Drop the OrtModelPackageApi struct, OrtApi::GetModelPackageApi,
  the OrtModelPackageAPI namespace, model_package_api.h, and the
  C++ wrappers/release glue in onnxruntime_cxx_api.h.
- Move the OrtModelPackageOptions/Context/ComponentContext opaque
  handle decls into onnxruntime_experimental_c_api.h.
- Add forward decls in experimental_c_api.cc so the registration
  table can take addresses of bodies defined in model_package_api.cc.
- Rename impls into namespace OrtExperimentalApis with the
  _SinceV28 suffix; bodies unchanged.
- Drop the Python bindings; per the design doc we start the
  experimental API in C/C++ only and prove it out before exposing
  it to Python.
- Update the autoep gtest to use a local ModelPackageFns struct
  populated through Ort::Experimental::Get_*_Fn lookups.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jambayk jambayk marked this pull request as ready for review June 10, 2026 19:36
@jambayk jambayk requested review from chilo-ms and edgchen1 June 10, 2026 19:36
- Drop the two CxxWrappers_* tests that depended on the removed
  Ort::ModelPackageContext / Ort::ModelPackageOptions C++ wrappers.
- Replace remaining pkg_api->X call sites with pkg_api.X now that
  GetModelPackageFns() returns a struct by reference.
- Replace ASSERT_NE(pkg_api, nullptr) with a null check on a canonical
  function pointer.
- Capture pkg_api by reference in lambdas.
- Drop a leftover Ort::ModelPackageOptions construction in
  FolderPath_ReturnsCorrectPath_WhenVariantJsonAbsent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jambayk jambayk enabled auto-merge (squash) June 10, 2026 20:30
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc
@edgchen1

edgchen1 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
  • The Python bindings (PyModelPackageContext / PyModelPackageOptions / PyModelPackageComponentContext and their onnxruntime.__init__ exports) are removed. Per the design doc we start the experimental API in C/C++ only.

it is a starting point. if we have a need for exposing experimental APIs in Python, we can explore how to do that.

Comment thread onnxruntime/test/autoep/test_model_package.cc
jambayk and others added 2 commits June 10, 2026 21:39
…kageApi_*

Mirror the documentation prose from the original OrtModelPackageApi
struct in onnxruntime_c_api.h. Cross-references are updated to the
new OrtModelPackageApi_* symbol names, and the OrtStatusPtr return
boilerplate is pulled in via the snippets.dox helper to match the
existing test sentinel's style.

Addresses review feedback from edgchen1.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GetModelPackageFns() previously accepted a nullptr from any failed
lookup, so a typo in the .inc symbol name would crash a test on a
null function-pointer call rather than surface as a clear error.

Centralize the validation in the lazy init via a small RESOLVE macro
that throws std::runtime_error naming the missing entry. gtest reports
the throw as a test failure with the symbol name in the message.

The per-test ASSERT_NE(pkg_api.CreateModelPackageContext, ...) lines
are now redundant and removed.

Addresses review feedback from chilo-ms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread onnxruntime/test/autoep/test_model_package.cc
@jambayk jambayk merged commit 2c4be91 into main Jun 11, 2026
88 checks passed
@jambayk jambayk deleted the jambayk/mp-experimental branch June 11, 2026 00:13
jambayk added a commit that referenced this pull request Jul 1, 2026
### Description

Builds out the standalone `model_package/` C library so a single library
covers the full lifecycle of an ONNX Runtime model package: inspection,
authoring, content-addressed shared assets, commit, prune, and
validation.
The library remains free of any dependency on ONNX Runtime itself.

**Public C API (`model_package/include/model_package.h`)**

- Lifecycle: `ModelPackage_Open` / `ModelPackage_New` /
`ModelPackage_Close`,
with `ModelPackageOpenOptions` controlling external-path access, symlink
  following, and strict unknown-field handling.
- Inspection: a POD `ModelPackageInfo` tree (`ModelPackage_Info`) plus
  by-name lookups for components, variants, and per-namespace
  `executor_info` entries, and round-trip JSON getters that preserve
  fields unknown to the current build.
- Path resolution: `ModelPackage_ResolveStringRef` implements the
package's
  resolution rules — relative paths anchored at a base directory,
  `sha256:<hex>[/sub/path]` for shared-asset content, and portable vs
  installed confinement (absolute paths and `..` segments only allowed
  under `layout: "installed"`).
- Shared assets: SHA-256 directory hashing,
`ModelPackage_AddSharedAsset`
  (with reproducible-build URI check and an optional `copy_in` staging
  mode), `ModelPackage_RemoveSharedAsset`, and
  `ModelPackage_ResolveAssetUri`. Assets under
  `<package_root>/shared_assets/` are auto-discovered at `Open`.
- Authoring: inline/external component setters, variant upsert/remove,
  per-namespace executor_info setters (inline and external), and
  package-level metadata / layout / `additional_metadata` setters.
  Mutations invalidate cached pointers in the mutated scope and its
  descendants.
- Commit / prune / validate: `ModelPackage_Commit` writes the in-memory
  model to disk either in place or to a fresh `dest_root` ("save as"),
  with `PRESERVE` or `DENSE` write modes; `ModelPackage_Prune` reclaims
  unreferenced files under `shared_assets/` and tracked orphan
  variant/component directories left behind by removals; and
  `ModelPackage_Validate` runs schema, path-reachability, asset-rehash,
  and unknown-field checks and returns a JSON report.
- Errors: opaque `ModelPackageStatus*` with a stable additive
  `ModelPackageErrorCode` enum (IO, schema, version, path confinement,
  asset missing, asset hash mismatch, not found, invalid arg, state).

**Internal layout**

The implementation is split into focused translation units:
`manifest_parser`, `model_package_impl`, `authoring`,
`commit_prune_validate`, `path_resolver`, `asset_hasher`, and an
in-tree `sha256`. Shared error plumbing lives in `status_impl.h`.

**ONNX Runtime integration (`onnxruntime/core/session/model_package/`)**

The ORT-side glue is wired onto the library through the C inspection
and path-resolution entry points. `model_package_context` now translates
the library's info tree into ORT-internal structs and parses the
`executor_info["ort"]` payload (`model_file`, `external_data`,
`session_options`, `provider_options`). When a variant declares
`external_data`, `CreateSessionForModelPackage` loads the model from a
memory mapping and passes the resolved folder to the session via
`kOrtSessionOptionsModelExternalInitializersFileFolderPath`, so external
initializers — including those backed by a shared asset — are picked up
at `Initialize` time.

The experimental `OrtModelPackageApi_*_SinceV28` C entries introduced in
#28990 are unchanged.

**Documentation and tests**

- `model_package/README.md` documents the on-disk layout, manifest and
  component schemas, shared-asset rules, path resolution, the authoring
  flow, and commit / prune / validate semantics.
- `onnxruntime/core/session/model_package/README.md` documents the ORT
  consumer-side glue: the `executor_info["ort"]` schema, the variant
  selection algorithm, the session-creation contract, and the registered
  experimental C entries.
- New library tests cover inspection, authoring, asset hashing, and
  commit (`model_package/tests/`). The ORT integration tests in
  `onnxruntime/test/autoep/test_model_package.cc` are reworked against
  the current C API surface.

### Motivation and Context

ORT needs a single library that owns the model package format end to
end — not just reading it, but producing it, validating it, and
maintaining it on disk with content-addressed shared assets.
Consolidating this behind one C API lets ORT, publisher tooling, and
third-party consumers share the same parser, path-resolution rules, and
on-disk invariants without each reimplementing them, and keeps the
library independent of the ORT session runtime.

---------

Co-authored-by: jambayk <jambayk@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: jambayk <jambay@github.com>
feich-ms pushed a commit that referenced this pull request Jul 3, 2026
### Description

Builds out the standalone `model_package/` C library so a single library
covers the full lifecycle of an ONNX Runtime model package: inspection,
authoring, content-addressed shared assets, commit, prune, and
validation.
The library remains free of any dependency on ONNX Runtime itself.

**Public C API (`model_package/include/model_package.h`)**

- Lifecycle: `ModelPackage_Open` / `ModelPackage_New` /
`ModelPackage_Close`,
with `ModelPackageOpenOptions` controlling external-path access, symlink
  following, and strict unknown-field handling.
- Inspection: a POD `ModelPackageInfo` tree (`ModelPackage_Info`) plus
  by-name lookups for components, variants, and per-namespace
  `executor_info` entries, and round-trip JSON getters that preserve
  fields unknown to the current build.
- Path resolution: `ModelPackage_ResolveStringRef` implements the
package's
  resolution rules — relative paths anchored at a base directory,
  `sha256:<hex>[/sub/path]` for shared-asset content, and portable vs
  installed confinement (absolute paths and `..` segments only allowed
  under `layout: "installed"`).
- Shared assets: SHA-256 directory hashing,
`ModelPackage_AddSharedAsset`
  (with reproducible-build URI check and an optional `copy_in` staging
  mode), `ModelPackage_RemoveSharedAsset`, and
  `ModelPackage_ResolveAssetUri`. Assets under
  `<package_root>/shared_assets/` are auto-discovered at `Open`.
- Authoring: inline/external component setters, variant upsert/remove,
  per-namespace executor_info setters (inline and external), and
  package-level metadata / layout / `additional_metadata` setters.
  Mutations invalidate cached pointers in the mutated scope and its
  descendants.
- Commit / prune / validate: `ModelPackage_Commit` writes the in-memory
  model to disk either in place or to a fresh `dest_root` ("save as"),
  with `PRESERVE` or `DENSE` write modes; `ModelPackage_Prune` reclaims
  unreferenced files under `shared_assets/` and tracked orphan
  variant/component directories left behind by removals; and
  `ModelPackage_Validate` runs schema, path-reachability, asset-rehash,
  and unknown-field checks and returns a JSON report.
- Errors: opaque `ModelPackageStatus*` with a stable additive
  `ModelPackageErrorCode` enum (IO, schema, version, path confinement,
  asset missing, asset hash mismatch, not found, invalid arg, state).

**Internal layout**

The implementation is split into focused translation units:
`manifest_parser`, `model_package_impl`, `authoring`,
`commit_prune_validate`, `path_resolver`, `asset_hasher`, and an
in-tree `sha256`. Shared error plumbing lives in `status_impl.h`.

**ONNX Runtime integration (`onnxruntime/core/session/model_package/`)**

The ORT-side glue is wired onto the library through the C inspection
and path-resolution entry points. `model_package_context` now translates
the library's info tree into ORT-internal structs and parses the
`executor_info["ort"]` payload (`model_file`, `external_data`,
`session_options`, `provider_options`). When a variant declares
`external_data`, `CreateSessionForModelPackage` loads the model from a
memory mapping and passes the resolved folder to the session via
`kOrtSessionOptionsModelExternalInitializersFileFolderPath`, so external
initializers — including those backed by a shared asset — are picked up
at `Initialize` time.

The experimental `OrtModelPackageApi_*_SinceV28` C entries introduced in
#28990 are unchanged.

**Documentation and tests**

- `model_package/README.md` documents the on-disk layout, manifest and
  component schemas, shared-asset rules, path resolution, the authoring
  flow, and commit / prune / validate semantics.
- `onnxruntime/core/session/model_package/README.md` documents the ORT
  consumer-side glue: the `executor_info["ort"]` schema, the variant
  selection algorithm, the session-creation contract, and the registered
  experimental C entries.
- New library tests cover inspection, authoring, asset hashing, and
  commit (`model_package/tests/`). The ORT integration tests in
  `onnxruntime/test/autoep/test_model_package.cc` are reworked against
  the current C API surface.

### Motivation and Context

ORT needs a single library that owns the model package format end to
end — not just reading it, but producing it, validating it, and
maintaining it on disk with content-addressed shared assets.
Consolidating this behind one C API lets ORT, publisher tooling, and
third-party consumers share the same parser, path-resolution rules, and
on-disk invariants without each reimplementing them, and keeps the
library independent of the ORT session runtime.

---------

Co-authored-by: jambayk <jambayk@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: jambayk <jambay@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants